#include <windows.h>
#include "util_win.h"
#include <stdio.h>

#ifdef WIN32

void InitConsoleWindow()
{
	int nCrt = 0;
	FILE* fp;
	AllocConsole();
	nCrt = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
	fp = _fdopen(nCrt, "w");
	*stdout = *fp;
	setvbuf(stdout, NULL, _IONBF, 0);
	//setlocale(LC_ALL, "");
	setlocale(LC_CTYPE, "chs");
}

void ConvertGBKToUtf8(std::string& amp, std::string strGBK)
{
	int len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)strGBK.c_str(), -1, NULL, 0);
	unsigned short * wszUtf8 = new unsigned short[len + 1];
	memset(wszUtf8, 0, len * 2 + 2);
	MultiByteToWideChar(CP_ACP, 0, (LPCSTR)strGBK.c_str(), -1, (LPWSTR)wszUtf8, len);
	len = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)wszUtf8, -1, NULL, 0, NULL, NULL);
	char *szUtf8 = new char[len + 1];
	memset(szUtf8, 0, len + 1);
	WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)wszUtf8, -1, szUtf8, len, NULL, NULL);
	//strGBK = szUtf8; 
	amp = szUtf8;
	delete[] szUtf8;
	delete[] wszUtf8;
}

void ConvertUtf8ToGBK(std::string&amp, std::string strUtf8)
{
	int len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)strUtf8.c_str(), -1, NULL, 0);
	unsigned short * wszGBK = new unsigned short[len + 1];
	memset(wszGBK, 0, len * 2 + 2);
	MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)strUtf8.c_str(), -1, (LPWSTR)wszGBK, len);
	len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)wszGBK, -1, NULL, 0, NULL, NULL);
	char *szGBK = new char[len + 1];
	memset(szGBK, 0, len + 1);
	WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)wszGBK, -1, szGBK, len, NULL, NULL);
	//strUtf8 = szGBK; 
	amp = szGBK;
	delete[] szGBK;
	delete[] wszGBK;
}

wchar_t * UTF8ToUnicode(const char* str)
{
	int textlen;
	wchar_t * result;
	textlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
	result = (wchar_t *)malloc((textlen + 1)*sizeof(wchar_t));
	ZeroMemory(result, (textlen + 1)*sizeof(wchar_t));
	MultiByteToWideChar(CP_UTF8, 0, str, -1, (LPWSTR)result, textlen);
	return result;
}

char * UnicodeToUTF8(const wchar_t* str)
{
	char* result;
	int textlen;
	textlen = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
	result = (char *)malloc((textlen + 1)*sizeof(char));
	ZeroMemory(result, sizeof(char)* (textlen + 1));
	WideCharToMultiByte(CP_UTF8, 0, str, -1, result, textlen, NULL, NULL);
	return result;
}

char * UnicodeToANSI(const wchar_t* str)
{
	char* result;
	int textlen;
	textlen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
	result = (char *)malloc((textlen + 1)*sizeof(char));
	ZeroMemory(result, sizeof(char)* (textlen + 1));
	WideCharToMultiByte(CP_ACP, 0, str, -1, result, textlen, NULL, NULL);
	return result;
}

char * UTF8ToANSI(const char* str)
{
	wchar_t* tmp = UTF8ToUnicode(str);
	char* result = UnicodeToANSI(tmp);
	free(tmp);
	return result;
}

wchar_t * ANSIToUnicode(const char* str)
{
	int textlen;
	wchar_t * result;
	textlen = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
	result = (wchar_t *)malloc((textlen + 1)*sizeof(wchar_t));
	ZeroMemory(result, (textlen + 1)*sizeof(wchar_t));
	MultiByteToWideChar(CP_ACP, 0, str, -1, (LPWSTR)result, textlen);
	return result;
}

#else

// ------------- on Mac OS or Linux platform --------------------
char* convert_gbk2utf8(char* in)
{
	if (in == NULL) {
		return NULL;
	}

	iconv_t converter = iconv_open("UTF-8", "GBK");
	if(converter == (iconv_t)(-1))
	{
		printf("Doesn't support convert GBK -> UTF-8! \n");
		return  NULL;
	}
	else
	{
		printf("Support GBK -> UTF8 !\n");
	}

	size_t insize;
	const char *input = in;//汉字随便加//应是const char *而不是char *

	insize = strlen(input);

	//存储转换结果的字符串
	size_t outsize = insize * 3+1;
	char *output = new char[outsize];
	char *output_old = output;//记录转换后的字符串的地址
	memset(output,0,outsize);

	//转换
	//size_t rc = iconv(conveter,(const char **)&input,&insize,&output_old,&outsize);
	size_t ret = iconv(converter, (char**)&input, &insize, &output_old, &outsize);
	//if(ret==(size_t)-1){
	//    std::cout<<"-------------------converting failed"<<std::endl;
	//    return output;  // strange . failed here but output has transfered string.
	//}

	//cout<<"output is : "<<output;
	//cout<<"  outsize="<<outsize<<endl;

	return output;
	iconv_close(converter);
}

#endif
// ------------- use standard C library to transfer -------------------
/* wide char to multi_char Unicode - ANSI*/
char* w2m(const wchar_t* wcs)
{
	char* buf;
	size_t len = wcstombs(NULL, wcs, 0);
	if (len == 0)
		return NULL;
	buf = (char *)malloc(sizeof(char)*(len + 1));
	ZeroMemory(buf, 0, sizeof(char)*(len + 1));
	len = wcstombs(buf, wcs, len + 1);
	return buf;
}
/* multi_char to wide_char ANSI - Unicode*/
wchar_t* m2w(const char* mbs)
{
	wchar_t* buf;
	if (mbs == NULL) {
		return NULL;
	}
	size_t len = mbstowcs(NULL, mbs, 0);
	if (len == 0)
		return NULL;
	buf = (wchar_t *)malloc(sizeof(wchar_t)*(len + 1));
	ZeroMemory(buf, 0, sizeof(wchar_t)*(len + 1));
	len = mbstowcs(buf, mbs, len + 1);
	return buf;
}

void echo_hexStr(char buf[], int len, const char* info)
{
	if (info == NULL)
		printf("HEXSTR =\n");
	else {
		printf("%s =\n", info);
	}

	for (int n = 0; n < len; n++){
		if (n % 20 == 0 && n > 0) {
			printf("\n");
		}
		printf("0x%.2x- ", buf[n]);
	}
	printf("\n");
}

void echoBinString(char in[], int len)
{
	for (int a = 0; a < len; a++) {
		byte aa = in[a];
		for (int i = 7; i > -1; i--)
		{
			int n = ((aa >> i) & 0x01) ? 1 : 0;
			printf("%d", n);
		}
		printf(" - ");

		if (((a + 1) % 4 == 0) && (a > 0)) {
			printf("\n");
		}
	}
}

//////////////////////////////////////////////////////////////////////////

unsigned char ToHex(unsigned char x)
{
	return  x > 9 ? x + 55 : x + 48;
}

unsigned char FromHex(unsigned char x)
{
	unsigned char y;
	if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;
	else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;
	else if (x >= '0' && x <= '9') y = x - '0';
	//else ASSERT(0);
	return y;
}

std::string UrlEncode(const std::string& str)
{
	std::string strTemp = "";
	size_t length = str.length();
	for (size_t i = 0; i < length; i++)
	{
		if (isalnum((unsigned char)str[i]) ||
			(str[i] == '-') ||
			(str[i] == '_') ||
			(str[i] == '.') ||
			(str[i] == '~'))
			strTemp += str[i];
		else if (str[i] == ' ')
			strTemp += "+";
		else
		{
			strTemp += '%';
			strTemp += ToHex((unsigned char)str[i] >> 4);
			strTemp += ToHex((unsigned char)str[i] % 16);
		}
	}
	return strTemp;
}

std::string UrlDecode(const std::string& str)
{
	std::string strTemp = "";
	size_t length = str.length();
	for (size_t i = 0; i < length; i++)
	{
		if (str[i] == '+') strTemp += ' ';
		else if (str[i] == '%')
		{
			//ASSERT(i + 2 < length);
			unsigned char high = FromHex((unsigned char)str[++i]);
			unsigned char low = FromHex((unsigned char)str[++i]);
			strTemp += high * 16 + low;
		}
		else strTemp += str[i];
	}
	return strTemp;
}

//////////////////////////////////////////////////////////////////////////
// win console color print 
//////////////////////////////////////////////////////////////////////////
//This will clear the console while setting the forground and
//background colors.

CRITICAL_SECTION gLogCs;

void ClearConsoleToColors(int ForgC, int BackC)
{
	WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);
	//Get the handle to the current output buffer...
	HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	//This is used to reset the carat/cursor to the top left.
	COORD coord = { 0, 0 };
	//A return value... indicating how many chars were written
	//not used but we need to capture this since it will be
	//written anyway (passing NULL causes an access violation).
	DWORD count;

	//This is a structure containing all of the console info
	// it is used here to find the size of the console.
	CONSOLE_SCREEN_BUFFER_INFO csbi;
	//Here we will set the current color
	SetConsoleTextAttribute(hStdOut, wColor);
	if (GetConsoleScreenBufferInfo(hStdOut, &csbi))
	{
		//This fills the buffer with a given character (in this case 32=space).
		FillConsoleOutputCharacter(hStdOut, (TCHAR)32, csbi.dwSize.X * csbi.dwSize.Y, coord, &count);

		FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
		//This will set our cursor position for the next print statement.
		SetConsoleCursorPosition(hStdOut, coord);
	}
}

//This will clear the console.
void ClearConsole()
{
	InitializeCriticalSection(&gLogCs);
	//Get the handle to the current output buffer...
	HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	//This is used to reset the carat/cursor to the top left.
	COORD coord = { 0, 0 };
	//A return value... indicating how many chars were written
	//   not used but we need to capture this since it will be
	//   written anyway (passing NULL causes an access violation).
	DWORD count;
	//This is a structure containing all of the console info
	// it is used here to find the size of the console.
	CONSOLE_SCREEN_BUFFER_INFO csbi;
	//Here we will set the current color
	if (GetConsoleScreenBufferInfo(hStdOut, &csbi))
	{
		//This fills the buffer with a given character (in this case 32=space).
		FillConsoleOutputCharacter(hStdOut, (TCHAR)32, csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
		FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
		//This will set our cursor position for the next print statement.
		SetConsoleCursorPosition(hStdOut, coord);
	}
}

//This will set the position of the cursor
void gotoXY(int x, int y)
{
	//Initialize the coordinates
	COORD coord = { x, y };
	//Set the position
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

//This will set the forground color for printing in a console window.
void SetColor(int ForgC)
{
	WORD wColor;
	//We will need this handle to get the current background attribute
	HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_SCREEN_BUFFER_INFO csbi;

	//We use csbi for the wAttributes word.
	if (GetConsoleScreenBufferInfo(hStdOut, &csbi))
	{
		//Mask out all but the background attribute, and add in the forgournd color
		wColor = (csbi.wAttributes & 0xF0) + (ForgC & 0x0F);
		SetConsoleTextAttribute(hStdOut, wColor);
	}
}

//This will set the forground and background color for printing in a console window.
void SetColorAndBackground(int ForgC, int BackC)
{
	WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);;
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wColor);
}

//Direct console output
void ConPrint(char *CharBuffer, int len)
{
	DWORD count;
	WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), CharBuffer, len, &count, NULL);
}

//Direct Console output at a particular coordinate.
void ConPrintAt(int x, int y, char *CharBuffer, int len)
{
	DWORD count;
	COORD coord = { x, y };
	HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hStdOut, coord);
	WriteConsole(hStdOut, CharBuffer, len, &count, NULL);
}

//Hides the console cursor
void HideTheCursor()
{
	CONSOLE_CURSOR_INFO cciCursor;
	HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

	if (GetConsoleCursorInfo(hStdOut, &cciCursor))
	{
		cciCursor.bVisible = FALSE;
		SetConsoleCursorInfo(hStdOut, &cciCursor);
	}
}

//Shows the console cursor
void ShowTheCursor()
{
	CONSOLE_CURSOR_INFO cciCursor;
	HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

	if (GetConsoleCursorInfo(hStdOut, &cciCursor))
	{
		cciCursor.bVisible = TRUE;
		SetConsoleCursorInfo(hStdOut, &cciCursor);
	}
}
//////////////////////////////////////////////////////////////////////////

// zc zh color log
// do NOT use EnterCriticalSection/Leave in log functions in case of outside use CS
void zclog(int color, const char* fmt, ...)
{
	//EnterCriticalSection(&gLogCs);
	va_list args;
	va_start(args, fmt);
	char msgbuf[4096];
	vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
	va_end(args);

	SetColor(color);
	printf("%s", msgbuf);
	//LeaveCriticalSection(&gLogCs);
}

void zctlog(int color, const char* fmt, ...)
{
	//EnterCriticalSection(&gLogCs);
	va_list args;
	va_start(args, fmt);
	char msgbuf[4096];
	vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
	va_end(args);

	SetColor(color);
	printf("%d * %s", GetCurrentThreadId(), msgbuf);
	//LeaveCriticalSection(&gLogCs);
}


void echo_hexStr(byte buf[], int len, const char* info)
{
	if (info == NULL)
		printf("HEXSTR = ");
	else {
		printf("%s = ", info);
	}

	int n;
	for (n = 0; n < len; n++){
		printf("%02x ", buf[n]);

		if ((buf[n - 1] == '\r') && (buf[n] == '\n')) {
			printf("\n");
		}

	}
	printf("\n");
}